package com.voice;

import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.LinkedList;

import android.app.Activity;
import android.content.Intent;
import android.media.MediaPlayer;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.view.View;
import android.view.WindowManager;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.TextView;

import com.alarm.R;
import com.gesture.ColorDetectionView;
import com.musicg.wave.Wave;
import com.musicg.wave.extension.Spectrogram;
import com.notification.NotificationSetting;

public class VoiceControlActivity extends Activity{

	private static final String TAG = "VoiceControlActivity";
	File path = new File(Environment.getExternalStorageDirectory().getPath() + "/WakeMeUp/");
	String recordingPath = path + "/recording.wav";
	NotificationSetting setting = new NotificationSetting();
	Button btnDiscard;
	Button btnRecord, startPlaybackButton;
	CheckBox cbKeep;
	TextView statusText;

	boolean isRecording = false;
	boolean isPlaying = false;
	ExtAudioRecorder audioRecorder;

	
	public VoiceControlActivity() {
		Log.i(TAG, "Instantiated new " + this.getClass());
		setting.load();
	}

	private double[] convert(double[][] array2D) {
		double[] rtn = new double[array2D.length+1];
		int i = 0;
		for (double[] array : array2D){
			double sum=0;
			for (double d : array)
				sum += d;
			rtn[i]=sum/array.length;
			if (rtn[i++] > rtn[rtn.length - 1])
				rtn[rtn.length - 1] = i;
		}
		return rtn;
	}
	public void onValidateClick(View v) {
		Log.i(TAG, "SetVoice.onValidateClick: " + path + "/original.wav");
		Log.i(TAG, "SetVoice.onValidateClick: " + recordingPath);
		Wave original = new Wave(path + "/original.wav");
		Wave current = new Wave(recordingPath);
		Spectrogram origSp = original.getSpectrogram(11025, 0);
		Spectrogram currSp = current.getSpectrogram(11025, 0);
		double d1[][] = origSp.getNormalizedSpectrogramData();
		double d2[][] = currSp.getNormalizedSpectrogramData();
		double[] originalSpec = convert(d2), currentSpec = convert(d1);

		TextView status = (TextView) findViewById(R.id.status);
		double similarity = matchProportion(originalSpec, currentSpec);
		Log.d(TAG, "TrackStatus.onPostExecute(): " + similarity);
		status.setText((similarity > 0.8 ? "Passed" : "Failed") + "\nSimilarity: " + similarity );
		Intent returnSetting = new Intent();
		if(similarity>0.8){
			returnSetting.putExtra("status", 1);
		} else
			returnSetting.putExtra("status", -1);
		setResult(Activity.RESULT_OK, returnSetting);
		finish();
	}

	static double matchProportion(double[] d1, double[] d2) {
		int shiftingFactor = 10;
		int match = 0;
		double threshold = 0.1;
		for (int i = 0; i < d1.length; i++) {
			if (i + 1 + shiftingFactor > d2.length)
				return (double) match / d2.length;
			if (similar(d1[i], Arrays.copyOfRange(d2, i, i + shiftingFactor), threshold))
				match++;
		}
		int len = (d1.length > d2.length ? d1.length : d2.length);
		Log.i(TAG, "Shifts:" + shiftingFactor + " Threshold:" + threshold + " Match:" + match + "/" + len);
		return (double) match / len;
	}

	private static boolean similar(double d1, double[] d2, double threshold) {
		for (double d : d2) {
			if (Math.abs(d1 - d) < threshold) {
				//Log.d(TAG, "True: " + (d));
				return true;
			}
			//Log.d(TAG, "False: " + Math.abs(d1 - d));
		}
		return false;
	}

	@Override
	protected void onPause() {
		Log.i(TAG, "onPause");
		super.onPause();
	}

	@Override
	protected void onResume() {
		Log.i(TAG, "onResume");
		super.onResume();
	}

	/** Called when the activity is first created. */
	@Override
	public void onCreate(Bundle bundle) {
		Log.i(TAG, "onCreate");
		super.onCreate(bundle);
		getWindow().addFlags(
				WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
						| WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
						| WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON);
		setContentView(R.layout.detect_voice);

		btnRecord = (Button) findViewById(R.id.StartRecordingButton);
		startPlaybackButton = (Button) findViewById(R.id.StartPlaybackButton);
		btnDiscard = (Button) findViewById(R.id.voiceDiscard);
		cbKeep = (CheckBox) findViewById(R.id.keep);
		btnRecord.setOnClickListener(new OnClickListener() {
			public void onClick(View v) {
				if (isRecording)
					stopRecording();
				else
					record();
			}
		});
		startPlaybackButton.setOnClickListener(new OnClickListener() {
			public void onClick(View v) {
				play();
			}
		});
		btnDiscard.setEnabled(setting.existVoice());
		path.mkdirs();
		record();
	}

	public void play() {
		Log.i(TAG, "SetVoice.play()");
		// startPlaybackButton.setEnabled(false);
		MediaPlayer mp = new MediaPlayer();
		try {
			mp.setDataSource(recordingPath);
			mp.prepare();
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (SecurityException e) {
			e.printStackTrace();
		} catch (IllegalStateException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		mp.start();
	}

	public void record() {
		Log.i(TAG, "SetVoice.record()");
		isRecording = true;
		btnDiscard.setEnabled(false);
		btnRecord.setText("Speak, then PRESS ME");
		if (cbKeep.isChecked()) {
			File recordingFile = new File(path + "/recording.wav");
			File originalFile = new File(path + "/original.wav");
			recordingFile.renameTo(originalFile);
		}
		audioRecorder = ExtAudioRecorder.getInstanse(false);
		audioRecorder.setOutputFile(recordingPath);
		audioRecorder.prepare();
		audioRecorder.start();
		TrackStatus track = new TrackStatus();
		track.execute();
	}

	public void stopRecording() {
		Log.i(TAG, "SetVoice.stopRecording()");
		audioRecorder.stop();
		audioRecorder.release();
		btnRecord.setText("Start Recording");
		setting.setVoice(recordingPath);
		startPlaybackButton.setEnabled(setting.existVoice());
		btnDiscard.setEnabled(true);
		startPlaybackButton.setEnabled(true);
		isRecording = false;
		onValidateClick(new View(this.getBaseContext()));
	}

	public void onCancel(View v) {
		setResult(Activity.RESULT_CANCELED);
		finish();
	}

	public class TrackStatus extends AsyncTask<Void, Integer, Void> {
		final int WAIT_Time = 1000, MAX_Time = 5 * WAIT_Time;
		int status = 0;

		@Override
		protected synchronized Void doInBackground(Void... params) {
			Log.d(TAG, "color: Background Process.");
			int time = 0;
			while (isRecording && time < MAX_Time) {
				try {
					wait(WAIT_Time);
					time += WAIT_Time;
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
			Log.d(TAG, "time: " + time);
			return null;
		}

		protected void onPostExecute(Void result) {
			if (isRecording)stopRecording();
		}
	}
}